include .default.env
include .env
export

build_dir    := build
js_build_dir := assets/js
entrypoints   = $(wildcard src/*.js)

# Misc variables.
export PATH             := vendor/bin:node_modules/.bin:$(PATH)
NPROC                   := 1

ifneq ($(OS),Windows_NT) # Not for Windows
UNAME_S := $(shell uname -s)
ifeq ($(UNAME_S),Darwin) # For Mac
SHELL                   := PATH=$(PATH) /bin/bash
NPROC                   := $(shell sysctl -n hw.logicalcpu)
else
SHELL                   := /bin/bash
NPROC                   := $(shell nproc)
endif
endif
override GIT_VERSION    := $(shell git --no-pager describe --always --tags)
override CUR_VERSION    := $(strip $(shell cat VERSION 2>/dev/null))
HOST                    := localhost
PORT                    := 8080
PHP_FLAGS               += -d xdebug.start_with_request=yes
PHPSTAN_FLAGS           += $(and $(CI),--no-progress)
COMPOSER_FLAGS          += $(and $(CI),--prefer-dist --no-progress)
ESBUILD_FLAGS           += --bundle --outdir=$(js_build_dir) --loader:.png=dataurl --splitting --format=esm --entry-names=[dir]/[name].bundle

# Files variables.
zip_release := dist/w_cms_$(GIT_VERSION).zip
phpcs_dir   := $(build_dir)/phpcs
phpunit_dir := $(build_dir)/phpunit
dirs        := $(phpcs_dir) $(phpunit_dir)

# Default target. This executes everything targets needed to get a fully
# working development environment.
.PHONY: all
all: vendor build

# Build generated files.
.PHONY: build
build: VERSION .BUILDDATE;

.PHONY: dev
dev: MAKEFLAGS += j2
dev:
	$(MAKE) serve watch

.PHONY: serve
serve: XDEBUG_MODE=debug
serve: vendor VERSION
	php -S $(HOST):$(PORT) -t ./ $(PHP_FLAGS)

# Run esbuild in watch mode.
.PHONY: watch
watch: node_modules
	@touch node_modules
	esbuild $(entrypoints) $(ESBUILD_FLAGS) --sourcemap=inline --watch=forever

# Create a new release and upload it on GitHub.
.PHONY: release-patch release-minor release-major
release-%: TAG = v$(shell semver -i $* `git describe --tags --abbrev=0`)
release-patch release-minor release-major: release-%: check node_modules
	git tag $(TAG)
	$(MAKE) dist
	git push --tags
	gh release create $(TAG)
	gh release upload $(TAG) dist/*.zip
	$(MAKE) .sentryrelease

# Inform Sentry of a new release.
.PHONY: .sentryrelease
.sentryrelease: build
	sentry-cli releases new $(GIT_VERSION)
	sentry-cli releases set-commits $(GIT_VERSION) --auto
	sentry-cli releases files $(GIT_VERSION) upload-sourcemaps $(js_build_dir) --url-prefix '~/$(js_build_dir)' --rewrite
	sentry-cli releases finalize $(GIT_VERSION)

# Generate the distribution files.
.PHONY: dist
dist: distclean buildclean
	@touch composer.lock
	$(MAKE) $(zip_release) DIST=1
	@touch composer.lock node_modules

# Build Zip release
dist/w_cms_%.zip: all
	mkdir -p $(dir $@)
# Include reuqired git tracked files (everything except ignored).
	@echo adding git files...
	@zip $@ \
		$(shell git ls-tree -r HEAD --name-only) \
		$(shell git ls-tree -r HEAD --name-only -d) \
		-x ".github/*" \
		-x "src/*" \
		-x "tests/*" \
		-x .default.env \
		-x .gitignore \
		-x codecov.yaml \
		-x composer.json \
		-x composer.lock \
		-x Makefile \
		-x package.json \
		-x package-lock.json \
		-x phpcs.xml \
		-x phpunit.xml \
		-x phpstan.neon
# Include additionnal untracked files
	@echo adding other files...
	@zip -r $@ \
		$(js_build_dir) \
		VERSION \
		vendor \
		-x "*.map" \
		-x "*/.*" \
		-x "*/doc/*" \
		-x "*/docs/*" \
		-x "*/example/*" \
		-x "*/test/*" \
		-x "*/tests/*"

.BUILDDATE: $(entrypoints) src/fn/fn.js node_modules
	esbuild $(entrypoints) $(ESBUILD_FLAGS) --sourcemap=$(if $(DIST),external,linked) --minify
	@date --iso-8601=seconds > $@

# Generate a .env file if none is present.
.env:
	cp .default.env $@

# Generate the VERSION file.
VERSION: .FORCE
ifneq ($(CUR_VERSION),$(GIT_VERSION))
	echo $(GIT_VERSION) > $@
endif



# Install PHP dependencies.
vendor: composer.json composer.lock
	composer install $(COMPOSER_FLAGS) $(if $(DIST),--no-dev --prefer-dist)
	touch $@

# Install JS dependencies.
node_modules: package.json package-lock.json
	npm install --no-progress --loglevel=error --also=dev
	touch $@

# Clean files generated by `make all`.
.PHONY: clean
clean: buildclean
	rm -rf $(build_dir)
	rm -rf vendor
	rm -rf node_modules
	rm -rf VERSION

# Clean files generated by `make dist`.
.PHONY: distclean
distclean:
	rm -rf dist

# Clean files generated by `make build`.
.PHONY: buildclean
buildclean:
	rm -rf $(js_build_dir) .BUILDDATE

# Run all checks.
.PHONY: check
check: lint analyse test

.PHONY: lint
lint: lint-php lint-js

# Lint php code.
.PHONY: lint-php
lint-php: lint-templates lint-app

# Run PHP syntax check on template files in parallel thanks to xargs
.PHONY: lint-templates
lint-templates:
	echo app/view/templates/*.php | xargs -P$(NPROC) -n1 php --syntax-check > /dev/null

# Lint backend php code with phpcs.
.PHONY: lint-app
lint-app: $(phpcs_dir) vendor
	phpcs --report-full --report-summary --cache=$(phpcs_dir)/result.cache || { printf "run 'make fix'\n\n"; exit 1; }

.PHONY: lint-js
lint-js: node_modules
	prettier -c 'src/**'


.PHONY: fix
fix: fix-php fix-js

# fix php code with phpcbf.
.PHONY: fix-php
fix-php: $(phpcs_dir) vendor
	phpcbf || exit 0

.PHONY: fix-js
fix-js: node_modules
	prettier --write 'src/**'

# Analyse php code with phpstan.
.PHONY: analyse
analyse: vendor
	phpstan analyse $(PHPSTAN_FLAGS)

# Test php code with phpunit.
.PHONY: test
test: XDEBUG_MODE=coverage
test: $(phpunit_dir) vendor
	phpunit

# Create dirs if the do not exist
$(dirs):
	mkdir -p $@

# Special (fake) target to always run a target but have Make consider
# this updated if it was actually rewritten (a .PHONY target is always
# considered new).
.FORCE: ;
